//
// MoviesTab.cs
// 
// Defines the tab responsible for handling Movies.
//
// Author:
//   Radu Tofoleanu <kenjiru.ro@gmail.com>
//
// Copyright (C) 2007-2008 Radu Tofoleanu (http://kenjiru.ro)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.IO;
using System.Data;
//using System.Data.OracleClient;
using System.Xml.Serialization;
using Gtk;
using Gdk;
using EigaLib;

namespace EigaApp
{
	public partial class MoviesTab : Gtk.Bin
	{
		// lucrul cu baza de date
		private EigaDb eigaDb = null;
		
		// variabile
		private TreeIter movieIter;
		private bool movieAdd = false;
		private bool movieEdit = false;
		
		public EigaDb DbConn
		{
			set { 
				eigaDb = value;
			}
		}
		
		public MoviesTab()
		{
			Build();
			
			Gdk.Pixbuf icon = Gdk.Pixbuf.LoadFromResource ("playlist.png");
			
			ListStore plStore = new ListStore (typeof(Gdk.Pixbuf), typeof(string), typeof(int));
			plStore.AppendValues (icon, "All Movies", 0);
			plStore.AppendValues (icon, "Own Movies", 1);
			plStore.AppendValues (icon, "Favorite Movies", 2);
			plStore.AppendValues (icon, "Wanna see Movies", 3);
			moviesPlaylist.Model = plStore;

			TreeViewColumn col1 = new TreeViewColumn ();
			col1.Title = "Movie lists";
			CellRendererPixbuf celrnd1 = new CellRendererPixbuf ();
			CellRendererText celrnd2 = new CellRendererText ();
			col1.PackStart (celrnd1, false);
			col1.PackStart (celrnd2, true);
			col1.SetAttributes (celrnd1, "pixbuf", 0);
			col1.SetAttributes (celrnd2, "text", 1);
			moviesPlaylist.AppendColumn (col1);
			
			ListStore movieListStore = new ListStore (typeof(int), typeof(string), typeof(int), 
				typeof(string), typeof(string));
			moviesList.AppendColumn ("Date", new CellRendererText (), "text", 2);
			moviesList.AppendColumn ("Title", new CellRendererText (), "text", 1);
			moviesList.AppendColumn ("Genre", new CellRendererText (), "text", 3);
			moviesList.AppendColumn ("Rating", new CellRendererText (), "text", 4);
			moviesList.Model = movieListStore;
			
			ListStore castStore = new ListStore (typeof(int), typeof(string), typeof(string));
			castList.AppendColumn ("Actor", new CellRendererText (), "text", 1);
			castList.AppendColumn ("Role", new CellRendererText (), "text", 2);
			castList.Model = castStore;
			
			movieDirector.Model = new ListStore (typeof(int), typeof(string));
			movieCountry.Model = new ListStore (typeof(int), typeof(string));;
			movieGenre.Model = new ListStore (typeof(int), typeof(string));;
			
			CellRendererText rnd1 = new CellRendererText ();
			movieDirector.PackStart(rnd1, true);
			movieDirector.SetAttributes(rnd1, "text", 1);
			
			CellRendererText rnd2 = new CellRendererText ();
			movieCountry.PackStart(rnd2, true);
			movieCountry.SetAttributes(rnd2, "text", 1);
			
			CellRendererText rnd3 = new CellRendererText ();
			movieGenre.PackStart(rnd3, true);
			movieGenre.SetAttributes(rnd3, "text", 1);
		}
		
		private void Message(string msg)
		{
			Gtk.MessageDialog msgDlg = new Gtk.MessageDialog(null, 
				DialogFlags.Modal,
				MessageType.Info,
				ButtonsType.Close, 
				msg);
			msgDlg.Run ();
			msgDlg.Destroy ();
		}
		
		private void MoviesBeginEdit()
		{
			if (movieEdit && movieIter.Stamp == 0) {
				movieEdit = false;
				return;
			}
			
			moviesEdit.Sensitive = false;
			moviesSave.Sensitive = true;
			moviesCancel.Sensitive = true;
			
			movieTitle.IsEditable = true;
			movieRating.IsEditable = true;
			movieDate.IsEditable = true;
			movieTag.IsEditable = true;
			movieCountry.Sensitive = true;
			movieDirector.Sensitive = true;
			movieGenre.Sensitive = true;
			
			detailsExpander.Expanded = true;
		}
		
		private void MoviesEndEdit()
		{
			moviesEdit.Sensitive = true;
			moviesSave.Sensitive = false;
			moviesCancel.Sensitive = false;
			
			movieTitle.IsEditable = false;
			movieRating.IsEditable = false;
			movieDate.IsEditable = false;
			movieTag.IsEditable = false;
			movieCountry.Sensitive = false;
			movieDirector.Sensitive = false;
			movieGenre.Sensitive = false;
			
			if (movieAdd == true) {
				moviesAdd.Sensitive = true;
				movieAdd = false;
			}
			if (movieEdit == true) {
				movieEdit = false;
			}
		}
		
		private void MoviesCancelEdit()
		{
			MoviesClear ();
		}
		
		private void MoviesClear ()
		{
			movieTitle.Text = "";
			movieDate.Text = "";
			movieTag.Text = "";
			movieRating.Text = "";
			movieGenre.Active = -1;
			movieDirector.Active = -1;
			movieCountry.Active = -1;
			
			ListStore castModel =  (ListStore) castList.Model;
			castModel.Clear();
			
			moviePicture.Pixbuf = Gdk.Pixbuf.LoadFromResource ("no_movie.jpg");
		}
		
		public void Refresh()
		{
			MoviesClear ();
			
			if (eigaDb.IsConnected() == false) {
				Console.WriteLine ("MoviesTab.cs: Refresh(): nu exista conexiune la baza de date!");
				return;
			}
			
			movieCountry.Model = eigaDb.GetAllCountries();
			movieGenre.Model = eigaDb.GetAllGenres();
			movieDirector.Model = eigaDb.GetAllDirectors();
		}
		
		private void LoadMoviesList(int listID)
		{
			if (eigaDb.IsConnected() == false) {
				Console.WriteLine ("MainWindow: LoadAllMovies(): nu exista conexiune la baza de date!");
				return;
			}
		
			// TODO: titlul trebuie sa-l obtin din lista cu categoriile de filme
			string[] titleArr = { "All Movies", "Own Movies", "Favorite Movies", "Wanna see Movies" };
			movieListTitle.Text = titleArr[listID];
			
			moviesList.Model = eigaDb.GetAllMovies (listID);
		}
		
		private void MoviesSaveEdit()
		{
			int id = (int) moviesList.Model.GetValue (movieIter, 0);
			string title = movieTitle.Text;
			int date = int.Parse (movieDate.Text);
			string tag = movieTag.Text;
			float rating = float.Parse (movieRating.Text);
			
			int countryID = 0;
			int genreID = 0;
			int directorID = 0;
			string genreStr = "";

			TreeIter cIter, gIter, dIter;
			if (movieCountry.GetActiveIter (out cIter) == true)
				countryID = (int) movieCountry.Model.GetValue (cIter, 0);
			if (movieGenre.GetActiveIter (out gIter) == true) {
				genreID = (int) movieGenre.Model.GetValue (gIter, 0);
				genreStr = (string) movieGenre.Model.GetValue (gIter, 1);
			}
			if (movieDirector.GetActiveIter (out dIter) == true)
				directorID = (int) movieDirector.Model.GetValue (dIter, 0);
			
			// testez daca datele sunt valide, adica nenule
			if(title == "" || tag == "" || date == 0 || rating == 0 || 
			   countryID == 0 || genreID == 0 || directorID == 0) {
				Message ("Stringurile nu pot fi nule!");
				return;
			}
			
			byte[] buff = moviePicture.Pixbuf.SaveToBuffer ("jpeg");
			
			if (eigaDb.EditMovie (id, title, tag, rating, date, countryID, 
			                      genreID, directorID, buff)) {
				ListStore store = (ListStore) moviesList.Model;
				store.SetValue (movieIter, 1, title);
				store.SetValue (movieIter, 2, date);
				store.SetValue (movieIter, 3, genreStr);
				store.SetValue (movieIter, 4, rating.ToString ());
			} else {
				Message ("Nu am putut salva modificarile!");
				MoviesCancelEdit();
			}
			MoviesEndEdit();
		}
		
		private void MoviesSaveAdd()
		{
			int id = 0;
			string title = movieTitle.Text;
			int date = int.Parse (movieDate.Text);
			string tag = movieTag.Text;
			float rating = float.Parse (movieRating.Text);
			
			int countryID = 0;
			int genreID = 0;
			int directorID = 0;
			string genreStr = "";

			TreeIter cIter, gIter, dIter;
			if (movieCountry.GetActiveIter (out cIter) == true)
				countryID = (int) movieCountry.Model.GetValue (cIter, 0);
			if (movieGenre.GetActiveIter (out gIter) == true) {
				genreID = (int) movieGenre.Model.GetValue (gIter, 0);
				genreStr = (string) movieGenre.Model.GetValue (gIter, 1);
			}
			if (movieDirector.GetActiveIter (out dIter) == true)
				directorID = (int) movieDirector.Model.GetValue (dIter, 0);
			
			// testez daca datele sunt valide, adica nenule
			if(title == "" || tag == "" || date == 0 || rating == 0 || 
			   countryID == 0 || genreID == 0 || directorID == 0) {
				Message ("Stringurile nu pot fi nule!");
				return;
			}
			
			byte[] buff = moviePicture.Pixbuf.SaveToBuffer ("jpeg");
			
			if (eigaDb.AddMovie (out id, title, tag, rating, date, countryID, genreID, directorID, buff)) {
				ListStore model = (ListStore) moviesList.Model;
				model.AppendValues (id, title, date, genreStr, rating.ToString ());
			} else {
				Message ("Nu am putut salva noua inregistrare!");
				MoviesCancelEdit ();
			}
			MoviesEndEdit ();
		}
		
		private void RefreshCast ()
		{
			int movieID = (int) moviesList.Model.GetValue (movieIter, 0);
			
			castList.Model = eigaDb.GetCast (movieID);
		}
		
		////////////////////////////////////////////////////////////////////////
		// Events
		////////////////////////////////////////////////////////////////////////

		protected virtual void OnMoviesPlaylistRowActivated(object o, Gtk.RowActivatedArgs args)
		{
			if (eigaDb.IsConnected() == false) {
				Console.WriteLine ("MainWindow: OnMoviesPlaylistRowActivated(): nu exista conexiune la baza de date!");
				return;
			}
			
			TreePath path = args.Path;
			TreeIter iter;
			
			moviesPlaylist.Model.GetIter (out iter, path);
			int listID = (int) moviesPlaylist.Model.GetValue (iter, 2);
			
			LoadMoviesList(listID);
		}

		protected virtual void OnMovieListRowActivated (object o, Gtk.RowActivatedArgs args)
		{
			if (eigaDb.IsConnected() == false) {
				Console.WriteLine ("MainWindow: OnMovieListRowActivated(): nu exista conexiune la baza de date!");
				return;
			}
			detailsExpander.Expanded = true;
			
			TreeView tr = o as TreeView;
			TreePath path = args.Path;
			
			tr.Model.GetIter (out movieIter, path);
			int movieID = (int) tr.Model.GetValue (movieIter, 0);
			
			int date, countryID, genreID, directorID;
			float rating;
			string title, tag;
			byte[] buff;
			
			if (eigaDb.GetMovie (movieID, out title, out tag, out rating, 
			                     out date, out countryID, out genreID, 
			                     out directorID, out buff)) {
				movieTitle.Text = title;
				movieDate.Text = date.ToString ();
				movieRating.Text = rating.ToString ();
				movieTag.Text = tag;
				
				if (buff == null || buff.Length == 0 ) {
					moviePicture.Pixbuf = Gdk.Pixbuf.LoadFromResource ("no_movie.jpg");
				} else {
					moviePicture.Pixbuf = new Pixbuf (buff);
				}
			} else {
				Message ("Nu am putut selecta filmul!");
				return;
			}
			
			// selectam directorul
			ListStore store = (ListStore) movieDirector.Model;
			TreeIter iter;
			if (store.GetIterFirst (out iter)) {
				do {
					int id = (int) store.GetValue (iter, 0);
					if (id == directorID) {
						movieDirector.SetActiveIter(iter);
						break;
					}
				} while (store.IterNext (ref iter));
			}
			// selectam tara
			store = (ListStore) movieCountry.Model;
			if (store.GetIterFirst (out iter)) {
				do {
					int id = (int) store.GetValue (iter, 0);
					if (id == countryID) {
						movieCountry.SetActiveIter(iter);
						break;
					}
				} while (store.IterNext (ref iter));
			}
			// selectam genul
			store = (ListStore) movieGenre.Model;
			if (store.GetIterFirst (out iter)) {
				do {
					int id = (int) store.GetValue (iter, 0);
					if (id == genreID) {
						movieGenre.SetActiveIter(iter);
						break;
					}
				} while (store.IterNext (ref iter));
			}

			RefreshCast ();
		}

		protected virtual void OnMoviesEditClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false) {
				Message ("Nu sunteti conectat la baza de date!");
				return;
			}
			
			movieEdit = true;
			MoviesBeginEdit ();
		}

		protected virtual void OnMoviesCancelClicked(object sender, System.EventArgs e)
		{
			MoviesClear ();
			MoviesCancelEdit ();
			MoviesEndEdit ();
		}

		protected virtual void OnMoviesSaveClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false || (movieEdit &&movieIter.Stamp == 0)) {
				if (eigaDb.IsConnected() == false)
					Message ("Nu sunteti conectat la baza de date!");
				
				MoviesCancelEdit ();
				MoviesEndEdit ();
				return;
			}
			
			if (movieAdd == true) {
				MoviesSaveAdd();
			} else {
				MoviesSaveEdit();
			}
		}

		protected virtual void OnMoviesAddClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false) {
				Message ("Nu sunteti conectat la baza de date!");
				return;
			}

			movieAdd = true;
			moviesAdd.Sensitive = false;
			
			MoviesBeginEdit();
			MoviesClear ();
		}

		protected virtual void OnActorsAddClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false || ! (movieAdd || movieEdit))
				return;
			
			ListStore store = (ListStore) moviesList.Model;
			int movieID = (int) store.GetValue (movieIter, 0);

			if (movieID == 0)
				return;
			
			AddActorsDialog addActorsDlg = new AddActorsDialog (eigaDb, movieID);
			addActorsDlg.DestroyEvent += new DestroyEventHandler (OnAddActorsDialogDestroy);
			addActorsDlg.Show ();
		}
		
		protected virtual void OnAddActorsDialogDestroy (object sender, DestroyEventArgs args)
		{
			RefreshCast ();
		}

		protected virtual void OnActorsRemoveClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false || ! (movieAdd || movieEdit))
				return;
			
			ListStore castStore = (ListStore) castList.Model;
			TreePath path;
			TreeIter iter;
			TreeViewColumn col;
			
			castList.GetCursor (out path, out col);
			castStore.GetIter (out iter, path);
			int entryID = (int) castStore.GetValue (iter, 0);
			
			if (eigaDb.RemoveFromCast (entryID)) {
				castStore.Remove (ref iter);
			} else {
				Message ("Nu am putut scoate actorul din cast!");
			}
		}

		protected virtual void OnImgButtonClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false || (movieAdd == false && movieEdit == false))
				return;
				
			FileFilter filter = new FileFilter ();
			filter.Name = "jpeg";
			filter.AddPattern ("*.jpeg");
			filter.AddPattern ("*.jpg");
			
			FileChooserDialog fc = new FileChooserDialog ("Alege o imagine",
				null,
				FileChooserAction.Open,
				"Cancel", ResponseType.Cancel,
				"Open", ResponseType.Accept);
			fc.Filter = filter;

			if (fc.Run () == (int) ResponseType.Accept) {
				byte[] buff = new byte[1000];
				int read;
				
				FileStream file = File.Open (fc.Filename, FileMode.Open);
				MemoryStream mem = new MemoryStream ();
				while ((read = file.Read (buff, 0, buff.Length)) > 0) {
					mem.Write (buff, 0, read);
				}
				file.Close();
				
				Pixbuf pixbuf = new Pixbuf (mem.ToArray ());
				moviePicture.Pixbuf = pixbuf;
          }
          fc.Destroy();
		}

		protected virtual void OnMoviesDeleteClicked(object sender, System.EventArgs e)
		{
			if (eigaDb.IsConnected() == false) {
				Message ("Nu sunteti conectat la baza de date!");
				return;
			}
			
			TreePath path;
			TreeIter iter;
			TreeViewColumn col;
			ListStore moviesStore = (ListStore) moviesList.Model;
			
			moviesList.GetCursor (out path, out col);
			if (! moviesStore.GetIter (out iter, path)) {
				Message ("Pentru a sterge un film, trebuie mai intai sa-l selectati!");
				return;
			}
			
			int movieID = (int) moviesList.Model.GetValue (iter, 0);
			
			if (eigaDb.DeleteMovie (movieID)) {
				MoviesClear ();

				if (iter.Stamp == movieIter.Stamp)
					movieIter.Stamp = 0;
				moviesStore.Remove (ref iter);
			} else {
				Message ("Nu am putut sterge inregistrare!");
			}
		}
	}
}
